import { CacheService } from '@app/cache';
import { OtaDevice } from '@app/db/entities/OtaDevice';
import { OtaTask } from '@app/db/entities/OtaTask';
import { Injectable } from '@nestjs/common';
import { Timeout } from '@nestjs/schedule';
import { DataSource, In } from 'typeorm';

@Injectable()
export class OtaService {
    public resListKey = 'ota:res:list'
    constructor(
        private cache:CacheService,
        protected dataSource: DataSource, 
    ){}

    @Timeout(5000)
    async run() {
        const msgs = await this.cache.client.rpop(this.resListKey, 50)
        if(!msgs || msgs.length == 0 ) {
            setTimeout(() => {
                this.run()
            }, 5000)

            return
        }

        const time = Math.floor(Date.now() / 1000)

        const tasks:{[key:string] : {success:number[],fail:number[]}} = {}
        msgs.forEach(msg => {
            const task = JSON.parse(msg)
            if(!tasks[task.msgId]) {
                tasks[task.msgId] = {
                    success : [],
                    fail : []
                }
            }

            if(task.s == 1) { //成功
                tasks[task.msgId].success.push(Number(task.id))
            }else {
                tasks[task.msgId].fail.push(Number(task.id))
            }
        })

        const queryRunner = await this.dataSource.createQueryRunner()
        await queryRunner.connect();
        await queryRunner.startTransaction();

        try {
            
            for(let k in tasks) {
                //const task =  tasks[k]
                const taskId = Number(k)

                const updateData:{[key in keyof OtaTask]? : OtaTask[key]} = {
                    
                }

                let task = await queryRunner.manager.findOne<OtaTask>(OtaTask, {
                    where : {id : taskId},
                    lock : {
                        mode : 'pessimistic_read'
                    }
                })

        

                if(tasks[k].success.length > 0) {
                    updateData.successCount = tasks[k].success.length
                    await queryRunner.manager.update<OtaDevice>(OtaDevice, {deviceId : tasks[k].success.length == 1 ? tasks[k].success[0] : In(tasks[k].success)}, {status : 1, completeTime : time})
                }

                if(tasks[k].fail.length > 0) {
                    updateData.failCount = tasks[k].fail.length
                    await queryRunner.manager.update<OtaDevice>(OtaDevice, {deviceId : tasks[k].fail.length == 1 ? tasks[k].fail[0] : In(tasks[k].fail)}, {status : 2, completeTime : time})
                }

                await queryRunner.manager.update<OtaTask>(OtaTask, {id : taskId}, updateData) 
            }


            await queryRunner.commitTransaction()

        } catch (error) {
            console.log('----------')
            console.log(error)
            await queryRunner.rollbackTransaction();
        } finally {
            await queryRunner.release();
        }


        setTimeout(() => {
            this.run()
        }, 1000)
        
    }
}
